package cn.com.dwr.service.impl;

import cn.com.dwr.common.dto.OrderDto;
import cn.com.dwr.entity.*;
import cn.com.dwr.mapper.AppCartItemMapper;
import cn.com.dwr.mapper.AppRefundMapper;
import cn.com.dwr.modules.app.mq.MqSender;
import cn.com.dwr.service.*;
import cn.com.dwr.utils.KdapiSearchUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.com.dwr.mapper.AppOrderMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
* @author 邓文润
* @description 针对表【app_order】的数据库操作Service实现
* @createDate 2023-12-12 07:13:55
*/
@Service
public class AppOrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder>
    implements AppOrderService{

    @Resource
    AppAddressService appAddressService;

    @Resource
    AppUserService appUserService;

    @Resource
    AppCartItemMapper appCartItemMapper;

    @Resource
    AppCartItemService appCartItemService;

    @Resource
    AppOrderItemService appOrderItemService;

    @Resource
    AppSkuStockService appSkuStockService;

    @Resource
    MqSender mqSender;

    @Resource
    AppRefundMapper appRefundMapper;

    @Resource
    AppProductService appProductService;

    /**
     * 购物车预览、立即购买的订单预览
     * @param orderDto
     * @return
     */
    @Override
    public Object preview(OrderDto orderDto) {

        long userId = appUserService.getCurrentUserId();

        // 判断参数是否完整
        Assert.isTrue(orderDto.getCartIds() != null
                || (orderDto.getProductId() != null && orderDto.getSkuId() != null && orderDto.getQuantity() != null),
                "参数不完整");

        // 获取收货地址
        // addressId为空，则展示默认收货地址，如果没有默认收货地址，则不展示
        AppAddress appAddress;
        if(orderDto.getAddressId() == null){
            appAddress = appAddressService.getDefault(userId);
        }else{
            // 不为空，则根据id获取收货地址
            appAddress = appAddressService.getById(orderDto.getAddressId());
            Assert.isTrue(appAddress.getUserId() == userId, "配送地址异常");
        }

        // 获取购物车信息
        List<AppCartItem> cartItems = getCartItemsByOrderDto(userId, orderDto);

        // 计算价格
        BigDecimal total = cartItems.stream()
                .map(item -> item.getPrice().multiply(new BigDecimal(item.getQuantity())))
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        // 优惠价、运费等信息
        BigDecimal freight = new BigDecimal("0");
        total = total.add(freight);

        return MapUtil.builder()
                .put("address", appAddress)
                .put("cartItems", cartItems)
                .put("total", total)
                .put("freight", freight)
                .build();
    }

    @Override
    public Object create(OrderDto orderDto) {

        long userId = appUserService.getCurrentUserId();

        // 判断收货地址
        AppAddress address = appAddressService.getById(orderDto.getAddressId());
        Assert.isTrue(address != null && address.getUserId() == userId, "收货地址异常");

        // 获取购物车或立即购买的商品信息
        List<AppCartItem> cartItems = getCartItemsByOrderDto(userId, orderDto);

        // 计算总金额
        BigDecimal total = cartItems.stream()
                .map(item -> item.getPrice().multiply(new BigDecimal(item.getQuantity())))
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        // 优惠价、运费等信息
        BigDecimal freight = new BigDecimal("0");
        total = total.add(freight);

        // 创建订单记录
        AppOrder appOrder = new AppOrder();
        appOrder.setUserId(userId);
        appOrder.setSn(generateOrderSn());

        appOrder.setTotalAmount(total);
        appOrder.setFreight(freight);

        // 收货人地址
        appOrder.setReceiverName(address.getName());
        appOrder.setReceiverTel(address.getTel());
        appOrder.setReceiverAddress(address.getAddressDetail());
        appOrder.setReceiverPostalCode(address.getPostalCode());
        appOrder.setReceiverAreaCode(address.getAreaCode());

        appOrder.setOrderStatus(0);

        appOrder.setIsDelete(false);
        appOrder.setCreated(LocalDateTime.now());
        appOrder.setNote(orderDto.getNote());

        this.save(appOrder);

        // 保存商品信息快照
        List<AppOrderItem> orderItems = new ArrayList<>();
        for (AppCartItem item : cartItems) {
            AppOrderItem orderItem = new AppOrderItem();
            orderItem.setProductId(item.getProductId());
            orderItem.setProductName(item.getProductName());
            orderItem.setProductImage(item.getProductImage());
            orderItem.setProductSn(item.getProductSn());
            orderItem.setCategoryId(item.getCategoryId());
            orderItem.setPrice(item.getPrice());
            orderItem.setQuantity(item.getQuantity());

            orderItem.setSkuId(item.getSkuId());
            orderItem.setSku(item.getSku());

            orderItem.setOrderId(appOrder.getId());
            orderItem.setCreated(LocalDateTime.now());

            orderItems.add(orderItem);
        }
        appOrderItemService.saveBatch(orderItems);

        // 删除购物车中的商品信息
        if(orderDto.getCartIds() != null && orderDto.getCartIds().size() > 0){
            appCartItemService.remove(new QueryWrapper<AppCartItem>()
                    .in("id", orderDto.getCartIds())
                    .eq("user_id", userId));
        }

        // 判断库存并扣减库存
        appSkuStockService.reduceStock(orderItems);

        // 未支付超时则自动取消订单
        mqSender.sendCancelOrderMessage(appOrder.getId());

        return appOrder.getSn();
    }

    @Override
    public AppOrder getBySn(String orderSn) {
        AppOrder appOrder = this.getOne(new QueryWrapper<AppOrder>()
                .eq("sn", orderSn));
        Assert.notNull(appOrder, "订单不存在");
        return appOrder;
    }

    @Override
    public AppOrder getOwnBySn(String orderSn) {
        AppOrder appOrder = getBySn(orderSn);
        long userId = appUserService.getCurrentUserId();
        Assert.isTrue(userId == appOrder.getUserId(), "无权限操作该订单");
        return appOrder;
    }

    @Override
    public AppOrder getOwnById(Long orderId) {
        AppOrder appOrder = this.getById(orderId);
        long userId = appUserService.getCurrentUserId();
        Assert.isTrue(userId == appOrder.getUserId(), "无权限操作该订单");
        return appOrder;
    }

    @Override
    public Object getOrderCount() {
        long userId = appUserService.getCurrentUserId();

        // 订单状态：0->待付款；1->待发货；2->待收货；3-已完成；4->已取消；5-申请退款，6->已退款，7->退款失败
        List<AppOrder> appOrders = this.list(new QueryWrapper<AppOrder>()
                .eq("user_id", userId));

        int unPay = 0;
        int unDeli = 0;
        int unRecv = 0;
        int unRefund = 0;

        long unComment = 0;

        for (AppOrder appOrder : appOrders) {
            if(appOrder.getOrderStatus() == 0){
                unPay ++;
            }else if(appOrder.getOrderStatus() == 1){
                unDeli ++;
            }else if(appOrder.getOrderStatus() == 2){
                unRecv ++;
            }else if(appOrder.getOrderStatus() == 5){
                unRefund ++;
            }
        }

        List<Integer> orderIds = appOrders.stream().filter(e -> e.getOrderStatus() == 3)
                .map(AppOrder::getOrderStatus).collect(Collectors.toList());
        if(!orderIds.isEmpty()){
            unComment = appOrderItemService.count(new QueryWrapper<AppOrderItem>()
                    .in("order_id", orderIds)
                    .isNull("comment_id"));
        }
        return MapUtil.builder()
                .put("unPay", unPay)
                .put("unDeli", unDeli)
                .put("unRecv", unRecv)
                .put("unRefund", unRefund)
                .put("unComment", unComment)
                .build();
    }

    @Override
    public Object getPage(Page page, long userId, Integer status) {

        Page<AppOrder> pageData = this.page(page, new QueryWrapper<AppOrder>()
                .eq("user_id", userId)
                .eq(status != null, "order_status", status)
                .orderByDesc("created"));

        for (AppOrder appOrder : pageData.getRecords()) {
            List<AppOrderItem> appOrderItems = appOrderItemService.listByOrderId(appOrder.getId());
            appOrder.setOrderItems(appOrderItems);
        }

        return pageData;
    }

    @Override
    public Object detail(Long id) {
        AppOrder appOrder = this.getOwnById(id);

        List<AppOrderItem> appOrderItems = appOrderItemService.listByOrderId(id);
        appOrder.setOrderItems(appOrderItems);

        if(Arrays.asList(5, 6).contains(appOrder.getOrderStatus())){
            // 退款单
            AppRefund appRefund = appRefundMapper.selectOne(new QueryWrapper<AppRefund>()
                    .eq("order_id", id));
            appOrder.setAppRefund(appRefund);
        }

        return appOrder;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancel(Long id) {
        AppOrder appOrder = this.getOwnById(id);

        Assert.isTrue(0 == appOrder.getOrderStatus(), "无法取消该订单");

        // 释放商品库存
        appSkuStockService.releaseStock(appOrder);

        appOrder.setOrderStatus(4);
        appOrder.setCompleteTime(LocalDateTime.now());
        appOrder.setUpdated(LocalDateTime.now());

        this.updateById(appOrder);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long id) {
        AppOrder appOrder = this.getOwnById(id);
        Assert.isTrue(Arrays.asList(0, 3, 4, 6).contains(appOrder.getOrderStatus()), "无法删除该订单");

        // 待付款的订单
        if(appOrder.getOrderStatus() == 0){
            // 释放商品库存
            appSkuStockService.releaseStock(appOrder);

            appOrder.setOrderStatus(4);
            appOrder.setCompleteTime(LocalDateTime.now());
        }

        appOrder.setUpdated(LocalDateTime.now());
        this.removeById(appOrder);
    }

    @Override
    public Object getDeliveryInfo(Long id) throws Exception {
        AppOrder appOrder = this.getOwnById(id);
        String deliveryInfo = new KdapiSearchUtil().getDeliveryInfo(appOrder.getDeliveryCompany(), appOrder.getDeliverySn());

        JSONArray traces = JSONUtil.parseObj(deliveryInfo).getJSONArray("Traces");

        List<Map<Object, Object>> list = traces.stream().map(e -> {
            JSONObject obj = JSONUtil.parseObj(e);

            return MapUtil.builder()
                    .put("acceptTime", obj.getStr("AcceptTime"))
                    .put("acceptStation", obj.getStr("AcceptStation"))
                    .put("remark", obj.getStr("Remark"))
                    .build();
        }).collect(Collectors.toList());

        return list;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void confirm(Long id) {
        AppOrder appOrder = this.getOwnById(id);
        Assert.isTrue(appOrder.getOrderStatus() == 2, "该订单无法确认收货");

        // 更新商品销量
        this.updateProductSale(id);

        appOrder.setOrderStatus(3);
        appOrder.setReceiveTime(LocalDateTime.now());
        appOrder.setUpdated(LocalDateTime.now());
        this.updateById(appOrder);
    }

    /**
     * 更新商品销量
     * @param orderId
     */
    private void updateProductSale(Long orderId) {
        List<AppOrderItem> orderItems = appOrderItemService.listByOrderId(orderId);

        List<AppProduct> products = new ArrayList<>();
        orderItems.forEach(item -> {
            AppProduct appProduct = appProductService.getById(item.getProductId());
            appProduct.setSale(appProduct.getSale() + item.getQuantity());
            products.add(appProduct);
        });

        appProductService.updateBatchById(products);
    }

    private String generateOrderSn() {
        String dateStr = DateUtil.format(new Date(), "yyMMddHHmm");
        return "D" + dateStr + RandomUtil.randomNumbers(4);
    }

    private List<AppCartItem> getCartItemsByOrderDto(long userId, OrderDto orderDto) {

        List<AppCartItem> cartItems;
        if(orderDto.getCartIds() != null){
            // 购物车购买
            cartItems = appCartItemMapper.getCartItemsWithProductInfo(new QueryWrapper<AppCartItem>()
                    .eq("user_id", userId)
                    .in("c.id", orderDto.getCartIds())
                    .orderByDesc("created"));
        }else{
            // 立即购买
            AppCartItem cartItem = appCartItemService.getCombinedCartItem(userId, orderDto.getProductId(),
                    orderDto.getSkuId(), orderDto.getQuantity());
            cartItems = new ArrayList<>();
            cartItems.add(cartItem);
        }
        return cartItems;
    }
}




